module Vote.Internal.Effect where

import Control.Monad.Logger (LogLevel (..), runStdoutLoggingT)
import qualified Control.Monad.Logger as L
import Data.Text (Text)
import Effectful (Dispatch (..), DispatchOf, Eff, Effect, IOE, (:>))
import Effectful.Dispatch.Dynamic (HasCallStack, interpret, send)
import Effectful.Error.Dynamic (Error, runErrorWith)
import Protolude (Monad (return), const, ($), (.))
import Vote.Internal.Entity (Err (..), Rep, repErr')

data Logging :: Effect where
  LogOtherN :: LogLevel -> Text -> Logging m ()

type instance DispatchOf Logging = Dynamic

logDebugN :: (HasCallStack, Logging :> es) => Text -> Eff es ()
logDebugN log = send (LogOtherN LevelDebug log)

logInfoN :: (HasCallStack, Logging :> es) => Text -> Eff es ()
logInfoN log = send (LogOtherN LevelInfo log)

logWarnN :: (HasCallStack, Logging :> es) => Text -> Eff es ()
logWarnN log = send (LogOtherN LevelWarn log)

logErrorN :: (HasCallStack, Logging :> es) => Text -> Eff es ()
logErrorN log = send (LogOtherN LevelError log)

logOtherN :: (HasCallStack, Logging :> es) => LogLevel -> Text -> Eff es ()
logOtherN level log = send (LogOtherN level log)

runLoggingIO :: (IOE :> es) => Eff (Logging : es) a -> Eff es a
runLoggingIO = interpret $ \_ -> \case
  LogOtherN level log -> runStdoutLoggingT $ L.logOtherN level log

--

catchRep :: Eff (Error Err : es) (Rep a) -> Eff es (Rep a)
catchRep = runErrorWith (const $ return . repErr')